#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>

#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>

#include <arpa/inet.h>

using namespace  std;
clock_t start_clock;
struct icmpheader {
	unsigned char icmp_type;
	unsigned char icmp_code;
	unsigned short int icmp_cksum;
	unsigned short int icmp_id;
	unsigned short int icmp_seq;
}; 

int sendUDP(int ttl, char * hname) {
	hostent *host = gethostbyname(hname);
	if(host == NULL) { perror("wrong host name");}
	
	struct udphdr udp;
	udp.source = htons(33434);
	udp.dest = htons(53);
	udp.len = htons(8);
	
	int sd;
	if ((sd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) < 0) {
		perror("raw socket");
		exit(1);
	}
	
	setsockopt(sd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
	
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = ((in_addr*)host->h_addr)->s_addr;
	
	int size = 0;
	start_clock = clock();
	if ((size = sendto(sd, &udp, sizeof(udp), 0, (struct sockaddr *)&sin, sizeof(struct sockaddr))) < 0)  {
		perror("sendto");
		exit(1);
	}
	//cout << "Sended " << ttl << " packet " << endl; 
	
	struct sockaddr_in sout;
	sout.sin_family = AF_INET;
	sout.sin_port = 0;
	sout.sin_addr.s_addr = INADDR_ANY;
	
	int rcv_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 
	if (bind(rcv_socket, (sockaddr *)&sout, sizeof(sout)) == -1) {
		perror("bind");
	}
	timeval timeout;
	timeout.tv_sec = 60;
	timeout.tv_usec = 0;
	setsockopt(rcv_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); 
	
	char packet[300];
	socklen_t a = sizeof(sout);
	size = recvfrom(rcv_socket, &packet, 300,  0, (struct sockaddr *)&sout, &a);
	if(size == -1) {
		cout << ttl << " * * *" << endl;
		//perror("receive");
		return -1;
	}
	struct icmpheader icmphdr;
	memcpy(&icmphdr, packet + 20,size-20); 
	cout << ttl << " " << inet_ntoa(sout.sin_addr) << " " << ((clock() - start_clock)*1000/CLOCKS_PER_SEC) << endl;
	if(icmphdr.icmp_type == 11) {
		return 11;
	}
	if(icmphdr.icmp_type == 0) {
		return 0;
	}
}

int main(int argc, char** argv) {
	cout << "Tracert " << argv[1]<< endl;
	for(int i = 0; i < 64 ; ++i) {
		if(sendUDP(i, argv[1]) == 0) {
			break;
		}
	}
	return 0;
}

